export = {}
/** 给接口描述的类型的赋值兼容性问题 */
/** 鸭式变形法，动态语言风格 */
//只要传入(或者赋值)的对象满足接口的必要条件，多余的字段也是被允许的；但如果我们已字面量的形式直接传入多余字段是不允许的
//
// interface Human {
//   name: string;
//   age: number;
// }
//
// ↓ 允许
// let x = {name: 'ahhh', age: 123, other: 'xxx'};
// let ahhh: Human = x;
//
// ↓ 不允许
//let ahhh2: Human = {name:'ahhh', age: 123, other: 'xxx'};
//
//
//接口原则上支持鸭式变形,但对象字面量(作为待赋的值或则实参)会被特殊对待而且会经过 额外属性检查(Excess Property Checks)。
//如果一个对象字面量存在任何“目标类型”不包含的属性时，你会得到一个错误。
//只能通过先赋值或者传参给一个临时的变量, 再把这个变量赋给这个接口对应的变量

interface Human {
  name: string;
  age: number;
}
// 非对象字面量支持鸭式变形
// 即 只要源对象上包含目标对象上要求的属性 即可通过验证
let x = {name: 'ahhh', age: 123, other: 'xxx'};
let ahhh: Human = x;

// 对象字面量(作为待赋的值或则实参)会被特殊对待而且会经过 额外属性检查(`Excess Property Checks`)，当将它们赋值给变量或作为参数传递的时候。 如果一个对象字面量存在任何“目标类型”不包含的属性时，你会得到一个错误
let ahhh2: Human = {name:'ahhh', age: 123, other: 'xxx'};
// ↑ TS2322: Type '{ name: string; age: number; other: string; }' is not assignable to type 'Human'.
// Object literal may only specify known properties, and 'other' does not exist in type 'Human'.


// 如果想要使用对象字面量形式 又想要跳过"额外属性检查 Excess Property Checks"
// 法一: 断言
let ahhh3: Human = {name:'ahhh', age: 123, other: 'xxx'} as Human;

// 法二: string index signature 字符串索引签名
interface Human2 {
  name: string;
  age: number;

  // other?: string;
  // ↑ 这么写有一个问题 有些用这个类型表示的变量可能并没有也不需要这个属性, 但我们依然可以点出来
  // So 你要么利用接口的合并 将变量分到不同的文件里 那些有other的 就在文件里再声明一个同名接口给他进行接口合并
  //
  // 但显然 我们的变量们 你并不希望因为这种原因就把它们分到不同的文件里去
  // 并且多个同名接口也会产生少许阅读上的混乱 (一般声明合并 我们只会用在希望扩展某个库的声明文件的时候)
  //
  //故↓
  [xxx/*←随便写 一般叫key*/: string/*←一般所有属性的key值都是字符串 包括symbol*/]: any;
  //↑ 表示可以有其它多余属性
}

let ahhh4: Human2 = {name: 'ahhh', age: 123, other: 'xxx'}; // 这样既能保证源对象上必须要有name、age属性,又允许源对象上拥有目标对象上没有定义的属性



/** 情景二:源数据作为函数实参传入
    和上面的规则是一样的*/
interface RectConfig {
  height: number;
  width: number;
}

function createRect(config: RectConfig/** 也可直接{height:number;width:number;}*/): void {

}

// 字面量形式传入多余字段对象
// let mySquare = createRect({width: 100, length: 222, color:'red'});
// ↑ TS2345: Argument of type '{ width: number; length: number; color: string; }' is not assignable to parameter of type 'RectConfig'.
// Object literal may only specify known properties, and 'color' does not exist in type 'RectConfig'.

let config = {
  width: 100,
  height: 200,
  color: 'red'
};

// 变量形式传入多余字段对象
let mySquare = createRect(config); // 不会报错

